﻿


    /// BitmapManipulator class, provides some useful static functions which 
    /// operate on .NET Bitmap objects in useful ways. 
    ///  
    /// Some of the useful features of this class incldue: 
    ///  
    ///   GetBitmapFromUri which downloads a bitmap from a URL, providing 
    ///   some useful error message elaboration logic to present users with a more meaningful 
    ///   error message in the event of a failure. 
    ///  
    ///   ConvertBitmap functions, which convert a bitmap from one format 
    ///   to another, including optional quality and compression parameters for codecs like JPEG and 
    ///   TIFF, respectively. 
    ///  
    ///   ScaleBitmap and ResizeBitmap, for modifying the dimensions 
    ///   of a bitmap (these are standard issue and boring, but nonetheless useful) 
    ///  
    ///   ThumbnailBitmap, a very useful function that produces a thumbnail of an image 
    ///   that fits within a given rectangle 
    ///  
    ///   OverlayBitmap, a useful function that overlays one bitmap atop another 
    ///   with a caller-defined alpha parameter.  Great for putting watermarks or logos on pictures. 
    ///  
    ///   A few other standard-issue image manipulation functions 
    ///  
    ///  
    /// NOTE: This code includes support for GIF en/decoding, via the .NET Framework's 
    /// System.Drawing classes.  However, in order to provide GIF functionality in your 
    /// application, you must license the LZW encoding scheme used in GIF files from Unisys. 
    /// As this is an opportunistic money-grab akin to SCO's, you are well advised to refuse 
    /// to do this, and instead favor PNG whenever possible. 
    ///  
    /// For more information, see http://www.microsoft.com/DEVONLY/Unisys.htm 
    ///  
    /// Current Version: 1.0.0 
    /// Revision History: 
    /// 1.0.0 - ajn - 9/1/2003 - First release 
    ///  
    /// Copyright(C) 2003 Adam J. Nelson. 
    ///  
    /// This code is hereby released for unlimited non-commercial and commercial use 
    ///  
    /// The author makes no guarantee regarding the fitness of this code, and hereby disclaims 
    /// all liability for any damage incurred as a result of using this code. 
    ///  
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Drawing.Drawing2D;
    using System.IO;
    using System.Net;

    namespace 地图拼接平移工具
    {
        ///  
        /// Utility class with static methods that do various useful things 
        /// with bitmaps that require multiple GDI+ calls with .NET CLR 
        /// <summary>
        /// 用C#写的图像处理的程序，包括旋转，实现JPEG BMP GIF TIFF PNG 的转换
        /// </summary>
        public static class BitmapManipulator
        {
            //MIME types for the various image formats 
            public const String MIME_JPEG = "image/jpeg";
            public const String MIME_PJPEG = "image/pjpeg";
            public const String MIME_GIF = "image/gif";
            public const String MIME_BMP = "image/bmp";
            public const String MIME_TIFF = "image/tiff";
            public const String MIME_PNG = "image/x-png";

            public class BitmapManipException : Exception
            {
                public BitmapManipException(String msg, Exception innerException)
                    : base(msg, innerException)
                {
                }
            }



            public static String[] supportedMimeTypes = new String[] {                                                               
			MIME_GIF,                                                                   
				MIME_JPEG, 
				MIME_PJPEG, 
				MIME_TIFF, 
				MIME_PNG, 
				MIME_BMP 
		};
            /// Converts a bitmap to a JPEG with a specific quality level 
            ///  
            /// Bitmap to convert 
            /// Specifies a quality from 0 (lowest) to 100 (highest), or -1 to leave 
            /// unspecified 
            ///  
            /// A new bitmap object containing the input bitmap converted. 
            ///     If the destination format and the target format are the same, returns 
            ///     a clone of the destination bitmap. 
            public static Bitmap ConvertBitmapToJpeg(this Bitmap inputBmp, int quality)
            {
                //If the dest format matches the source format and quality not changing, just clone 
                if (inputBmp.RawFormat.Equals(ImageFormat.Jpeg) && quality == -1)
                {
                    return (Bitmap)inputBmp.Clone();
                }

                //Create an in-memory stream which will be used to save 
                //the converted image 
                System.IO.Stream imgStream = new System.IO.MemoryStream();

                //Get the ImageCodecInfo for the desired target format 
                ImageCodecInfo destCodec = FindCodecForType(MimeTypeFromImageFormat(ImageFormat.Jpeg));

                if (destCodec == null)
                {
                    //No codec available for that format 
                    throw new ArgumentException("The requested format " +
                                                MimeTypeFromImageFormat(ImageFormat.Jpeg) +
                                                " does not have an available codec installed",
                                                "destFormat");
                }

                //Create an EncoderParameters collection to contain the 
                //parameters that control the dest format's encoder 
                EncoderParameters destEncParams = new EncoderParameters(1);

                //Use quality parameter 
                EncoderParameter qualityParam = new EncoderParameter(Encoder.Quality, quality);
                destEncParams.Param[0] = qualityParam;

                //Save w/ the selected codec and encoder parameters 
                inputBmp.Save(imgStream, destCodec, destEncParams);

                //At this point, imgStream contains the binary form of the 
                //bitmap in the target format.  All that remains is to load it 
                //into a new bitmap object 
                Bitmap destBitmap = new Bitmap(imgStream);

                //Free the stream 
                //imgStream.Close(); 
                //For some reason, the above causes unhandled GDI+ exceptions 
                //when destBitmap.Save is called.  Perhaps the bitmap object reads 
                //from the stream asynchronously? 

                return destBitmap;
            }

            /// Converts a bitmap to a Tiff with a specific compression 
            ///  
            /// Bitmap to convert 
            /// The compression to use on the TIFF file output.  Be warned that the CCITT3, CCITT4, 
            ///     and RLE compression options are only applicable to TIFFs using a palette index color depth  
            ///     (that is, 1, 4, or 8 bpp).  Using any of these compression schemes with 24 or 32-bit  
            ///     TIFFs will throw an exception from the bowels of GDI+ 
            ///  
            /// A new bitmap object containing the input bitmap converted. 
            ///     If the destination format and the target format are the same, returns 
            ///     a clone of the destination bitmap. 
            public static Bitmap ConvertBitmapToTiff(this Bitmap inputBmp, TiffCompressionEnum compression)
            {
                //If the dest format matches the source format and quality/bpp not changing, just clone 
                if (inputBmp.RawFormat.Equals(ImageFormat.Tiff) && compression == TiffCompressionEnum.Unspecified)
                {
                    return (Bitmap)inputBmp.Clone();
                }

                if (compression == TiffCompressionEnum.Unspecified)
                {
                    //None of the params are chaning; use the general purpose converter 
                    return ConvertBitmap(inputBmp, ImageFormat.Tiff);
                }

                //Create an in-memory stream which will be used to save 
                //the converted image 
                System.IO.Stream imgStream = new System.IO.MemoryStream();

                //Get the ImageCodecInfo for the desired target format 
                ImageCodecInfo destCodec = FindCodecForType(MimeTypeFromImageFormat(ImageFormat.Tiff));

                if (destCodec == null)
                {
                    //No codec available for that format 
                    throw new ArgumentException("The requested format " +
                                                MimeTypeFromImageFormat(ImageFormat.Tiff) +
                                                " does not have an available codec installed",
                                                "destFormat");
                }


                //Create an EncoderParameters collection to contain the 
                //parameters that control the dest format's encoder 
                EncoderParameters destEncParams = new EncoderParameters(1);

                //set the compression parameter 
                EncoderValue compressionValue;

                switch (compression)
                {
                    case TiffCompressionEnum.CCITT3:
                        compressionValue = EncoderValue.CompressionCCITT3;
                        break;

                    case TiffCompressionEnum.CCITT4:
                        compressionValue = EncoderValue.CompressionCCITT4;
                        break;

                    case TiffCompressionEnum.LZW:
                        compressionValue = EncoderValue.CompressionLZW;
                        break;

                    case TiffCompressionEnum.RLE:
                        compressionValue = EncoderValue.CompressionRle;
                        break;

                    default:
                        compressionValue = EncoderValue.CompressionNone;
                        break;
                }
                EncoderParameter compressionParam = new EncoderParameter(Encoder.Compression, (long)compressionValue);

                destEncParams.Param[0] = compressionParam;

                //Save w/ the selected codec and encoder parameters 
                inputBmp.Save(imgStream, destCodec, destEncParams);

                //At this point, imgStream contains the binary form of the 
                //bitmap in the target format.  All that remains is to load it 
                //into a new bitmap object 
                Bitmap destBitmap = new Bitmap(imgStream);

                //Free the stream 
                //imgStream.Close(); 
                //For some reason, the above causes unhandled GDI+ exceptions 
                //when destBitmap.Save is called.  Perhaps the bitmap object reads 
                //from the stream asynchronously? 

                return destBitmap;
            }

            /// Converts a bitmap to another bitmap format, returning the new converted 
            ///     bitmap 
            ///  
            ///  
            /// Bitmap to convert 
            /// MIME type of format to convert to 
            ///  
            /// A new bitmap object containing the input bitmap converted. 
            ///     If the destination format and the target format are the same, returns 
            ///     a clone of the destination bitmap. 
            public static Bitmap ConvertBitmap(this Bitmap inputBmp, String destMimeType)
            {
                return ConvertBitmap(inputBmp, ImageFormatFromMimeType(destMimeType));
            }

            /// Converts a bitmap to another bitmap format, returning the new converted 
            ///     bitmap 
            ///  
            ///  
            /// Bitmap to convert 
            /// Bitmap format to convert to 
            ///  
            /// A new bitmap object containing the input bitmap converted. 
            ///     If the destination format and the target format are the same, returns 
            ///     a clone of the destination bitmap. 
            public static Bitmap ConvertBitmap(this Bitmap inputBmp, System.Drawing.Imaging.ImageFormat destFormat)
            {
                //If the dest format matches the source format and quality/bpp not changing, just clone 
                if (inputBmp.RawFormat.Equals(destFormat))
                {
                    return (Bitmap)inputBmp.Clone();
                }

                //Create an in-memory stream which will be used to save 
                //the converted image 
                System.IO.Stream imgStream = new System.IO.MemoryStream();

                //Save the bitmap out to the memory stream, using the format indicated by the caller 
                inputBmp.Save(imgStream, destFormat);

                //At this point, imgStream contains the binary form of the 
                //bitmap in the target format.  All that remains is to load it 
                //into a new bitmap object 
                Bitmap destBitmap = new Bitmap(imgStream);

                //Free the stream 
                //imgStream.Close(); 
                //For some reason, the above causes unhandled GDI+ exceptions 
                //when destBitmap.Save is called.  Perhaps the bitmap object reads 
                //from the stream asynchronously? 

                return destBitmap;
            }

            ///  
            /// Scales a bitmap by a scale factor, growing or shrinking both axes while 
            /// maintaining the original aspect ratio 
            ///  
            /// Bitmap to scale 
            /// Factor by which to scale 
            /// New bitmap containing image from inputBmp, scaled by the scale factor 
            public static Bitmap ScaleBitmap(this Bitmap inputBmp, double scaleFactor)
            {
                return ScaleBitmap(inputBmp, scaleFactor, scaleFactor);
            }

            ///  
            /// Scales a bitmap by a scale factor, growing or shrinking both axes independently,  
            /// possibly changing the aspect ration 
            ///  
            /// Bitmap to scale 
            /// Factor by which to scale 
            /// New bitmap containing image from inputBmp, scaled by the scale factor 
            public static Bitmap ScaleBitmap(this Bitmap inputBmp, double xScaleFactor, double yScaleFactor)
            {
                //Create a new bitmap object based on the input 
                Bitmap newBmp = new Bitmap(
                                          (int)(inputBmp.Size.Width * xScaleFactor),
                                          (int)(inputBmp.Size.Height * yScaleFactor),
                                          PixelFormat.Format24bppRgb);//Graphics.FromImage doesn't like Indexed pixel format 

                //Create a graphics object attached to the new bitmap 
                Graphics newBmpGraphics = Graphics.FromImage(newBmp);

                //Set the interpolation mode to high quality bicubic  
                //interpolation, to maximize the quality of the scaled image 
                newBmpGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

                newBmpGraphics.ScaleTransform((float)xScaleFactor, (float)yScaleFactor);

                //Draw the bitmap in the graphics object, which will apply 
                //the scale transform 
                //Note that pixel units must be specified to ensure the framework doesn't attempt 
                //to compensate for varying horizontal resolutions in images by resizing; in this case, 
                //that's the opposite of what we want. 
                Rectangle drawRect = new Rectangle(0, 0, inputBmp.Size.Width, inputBmp.Size.Height);
                newBmpGraphics.DrawImage(inputBmp, drawRect, drawRect, GraphicsUnit.Pixel);

                //Return the bitmap, as the operations on the graphics object 
                //are applied to the bitmap 
                newBmpGraphics.Dispose();

                //newBmp will have a RawFormat of MemoryBmp because it was created 
                //from scratch instead of being based on inputBmp.  Since it it inconvenient 
                //for the returned version of a bitmap to be of a different format, now convert 
                //the scaled bitmap to the format of the source bitmap 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            ///  
            /// Resizes a bitmap's width and height independently 
            ///  
            /// Bitmap to resize 
            /// New width 
            /// New height 
            /// Resized bitmap 
            public static Bitmap ResizeBitmap(this Bitmap inputBmp, int imgWidth, int imgHeight)
            {
                //Simply compute scale factors that result in the desired size, then call ScaleBitmap 
                return ScaleBitmap(inputBmp,
                                   (float)imgWidth / (float)inputBmp.Size.Width,
                                   (float)imgHeight / (float)inputBmp.Size.Height);
            }

            ///  
            /// Generates a thumbnail of the bitmap.  This is effectively a specialized 
            /// resize function, which maintains the aspect ratio of the image while 
            /// resizing it to ensure that both its width and height are within 
            /// caller-specified maximums 
            ///  
            /// Bitmap for which to generate thumbnail 
            /// Maximum width of thumbnail 
            /// Maximum height of thumbnail 
            /// Thumbnail of inputBmp w/ the same aspect ratio, but 
            /// width and height both less than or equal to the maximum limits 
            public static Bitmap ThumbnailBitmap(this Bitmap inputBmp, int maxWidth, int maxHeight)
            {
                //Compute the scaling factor that will scale the bitmap witdh 
                //to the max width, and the other scaling factor that will scale 
                //the bitmap height to the max height. 
                //Apply the lower of the two, then if the other dimension is still 
                //outside the caller-defined limits, compute the scaling factor 
                //which will bring that dimension within the limits. 
                double widthScaleFactor = (double)maxWidth / (double)inputBmp.Size.Width;
                double heightScaleFactor = (double)maxHeight / (double)inputBmp.Size.Height;
                double finalScaleFactor = 0;

                //Now pick the smaller scale factor 
                if (widthScaleFactor < heightScaleFactor)
                {
                    //If this scale factor doesn't bring the height 
                    //within the required maximum, combine this width 
                    //scale factor with an additional scaling factor 
                    //to take the height the rest of the way down 
                    if ((double)inputBmp.Size.Height * widthScaleFactor > maxHeight)
                    {
                        //Need to scale height further 
                        heightScaleFactor = (double)(maxHeight * widthScaleFactor) / (double)inputBmp.Size.Height;

                        finalScaleFactor = widthScaleFactor * heightScaleFactor;
                    }
                    else
                    {
                        //Width scale factor brings both dimensions inline sufficiently 
                        finalScaleFactor = widthScaleFactor;
                    }
                }
                else
                {
                    //Else, height scale factor is smaller than width. 
                    //Apply the same logic as above, but with the roles of the width 
                    //and height scale factors reversed 
                    if ((double)inputBmp.Size.Width * heightScaleFactor > maxWidth)
                    {
                        //Need to scale height further 
                        widthScaleFactor = (double)(maxWidth * heightScaleFactor) / (double)inputBmp.Size.Width;

                        finalScaleFactor = widthScaleFactor * heightScaleFactor;
                    }
                    else
                    {
                        //Height scale factor brings both dimensions inline sufficiently 
                        finalScaleFactor = heightScaleFactor;
                    }
                }

                return ScaleBitmap(inputBmp, finalScaleFactor);
            }

            public static Bitmap RotateBitmapRight90(this Bitmap inputBmp)
            {
                //Copy bitmap 
                Bitmap newBmp = (Bitmap)inputBmp.Clone();

                newBmp.RotateFlip(RotateFlipType.Rotate90FlipNone);

                //The RotateFlip transformation converts bitmaps to memoryBmp, 
                //which is uncool.  Convert back now 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            public static Bitmap RotateBitmapRight180(this Bitmap inputBmp)
            {
                //Copy bitmap 
                Bitmap newBmp = (Bitmap)inputBmp.Clone();

                newBmp.RotateFlip(RotateFlipType.Rotate180FlipNone);


                //The RotateFlip transformation converts bitmaps to memoryBmp, 
                //which is uncool.  Convert back now 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            public static Bitmap RotateBitmapRight270(this Bitmap inputBmp)
            {
                //Copy bitmap 
                Bitmap newBmp = (Bitmap)inputBmp.Clone();

                newBmp.RotateFlip(RotateFlipType.Rotate270FlipNone);


                //The RotateFlip transformation converts bitmaps to memoryBmp, 
                //which is uncool.  Convert back now 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            ///  
            /// Reverses a bitmap, effectively rotating it 180 degrees in 3D space about 
            /// the Y axis.  Results in a "mirror image" of the bitmap, reversed much 
            /// as it would be in a mirror 
            ///  
            ///  
            ///  
            public static Bitmap ReverseBitmap(this Bitmap inputBmp)
            {
                //Copy the bitmap to a new bitmap object 
                Bitmap newBmp = (Bitmap)inputBmp.Clone();

                //Flip the bitmap 
                newBmp.RotateFlip(RotateFlipType.RotateNoneFlipX);


                //The RotateFlip transformation converts bitmaps to memoryBmp, 
                //which is uncool.  Convert back now 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            ///  
            /// Reverses a bitmap, effectively rotating it 180 degrees in 3D space about 
            /// the X axis.  Results in an upside-down view of the image 
            ///  
            ///  
            ///  
            public static Bitmap FlipBitmap(this Bitmap inputBmp)
            {
                //Copy the bitmap to a new bitmap object 
                Bitmap newBmp = (Bitmap)inputBmp.Clone();

                //Flip the bitmap 
                newBmp.RotateFlip(RotateFlipType.RotateNoneFlipY);


                //The RotateFlip transformation converts bitmaps to memoryBmp, 
                //which is uncool.  Convert back now 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            ///  
            /// Renders a bitmap over another bitmap, with a specific alpha value. 
            /// This can be used to overlay a logo or watermark over a bitmap 
            ///  
            /// Bitmap over which image is to be overlaid 
            /// Bitmap to overlay 
            /// Alpha value fo overlay bitmap.  0 = fully transparent, 100 = fully opaque 
            /// Location in destination bitmap where overlay image will be placed 
            ///  
            public static Bitmap OverlayBitmap(this Bitmap destBmp, Bitmap bmpToOverlay, int overlayAlpha, Point overlayPoint)
            {
                //Convert alpha to a 0..1 scale 
                float overlayAlphaFloat = (float)overlayAlpha / 100.0f;

                //Copy the destination bitmap 
                //NOTE: Can't clone here, because if destBmp is indexed instead of just RGB,  
                //Graphics.FromImage will fail 
                Bitmap newBmp = new Bitmap(destBmp.Size.Width,
                                           destBmp.Size.Height);

                //Create a graphics object attached to the bitmap 
                Graphics newBmpGraphics = Graphics.FromImage(newBmp);

                //Draw the input bitmap into this new graphics object 
                newBmpGraphics.DrawImage(destBmp,
                                         new Rectangle(0, 0,
                                                       destBmp.Size.Width,
                                                       destBmp.Size.Height),
                                         0, 0, destBmp.Size.Width, destBmp.Size.Height,
                                         GraphicsUnit.Pixel);

                //Create a new bitmap object the same size as the overlay bitmap 
                Bitmap overlayBmp = new Bitmap(bmpToOverlay.Size.Width, bmpToOverlay.Size.Height);

                //Make overlayBmp transparent 
                overlayBmp.MakeTransparent(overlayBmp.GetPixel(0, 0));

                //Create a graphics object attached to the bitmap 
                Graphics overlayBmpGraphics = Graphics.FromImage(overlayBmp);

                //Create a color matrix which will be applied to the overlay bitmap 
                //to modify the alpha of the entire image 
                float[][] colorMatrixItems = { 
				new float[] {1, 0, 0, 0, 0}, 
					new float[] {0, 1, 0, 0, 0}, 
					new float[] {0, 0, 1, 0, 0}, 
					new float[] {0, 0, 0, overlayAlphaFloat, 0},  
					new float[] {0, 0, 0, 0, 1} 
			};

                ColorMatrix colorMatrix = new ColorMatrix(colorMatrixItems);

                //Create an ImageAttributes class to contain a color matrix attribute 
                ImageAttributes imageAttrs = new ImageAttributes();
                imageAttrs.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

                //Draw the overlay bitmap into the graphics object, applying the image attributes 
                //which includes the reduced alpha 
                Rectangle drawRect = new Rectangle(0, 0, bmpToOverlay.Size.Width, bmpToOverlay.Size.Height);
                overlayBmpGraphics.DrawImage(bmpToOverlay,
                                             drawRect,
                                             0, 0, bmpToOverlay.Size.Width, bmpToOverlay.Size.Height,
                                             GraphicsUnit.Pixel,
                                             imageAttrs);
                overlayBmpGraphics.Dispose();

                //overlayBmp now contains bmpToOverlay w/ the alpha applied. 
                //Draw it onto the target graphics object 
                //Note that pixel units must be specified to ensure the framework doesn't attempt 
                //to compensate for varying horizontal resolutions in images by resizing; in this case, 
                //that's the opposite of what we want. 
                newBmpGraphics.DrawImage(overlayBmp,
                                         new Rectangle(overlayPoint.X, overlayPoint.Y, bmpToOverlay.Width, bmpToOverlay.Height),
                                         drawRect,
                                         GraphicsUnit.Pixel);

                newBmpGraphics.Dispose();

                //Recall that newBmp was created as a memory bitmap; convert it to the format 
                //of the input bitmap 
                return ConvertBitmap(newBmp, destBmp.RawFormat); ;
            }

            ///  
            /// Renders a bitmap over another bitmap, with a specific alpha value. 
            /// This can be used to overlay a logo or watermark over a bitmap 
            ///  
            /// Bitmap over which image is to be overlaid 
            /// Bitmap to overlay 
            /// Alpha value fo overlay bitmap.  0 = fully transparent, 100 = fully opaque 
            /// Corner of destination bitmap to place overlay bitmap 
            ///  
            public static Bitmap OverlayBitmap(this Bitmap destBmp, Bitmap bmpToOverlay, int overlayAlpha, ImageCornerEnum corner)
            {
                //Translate corner to rectangle and pass through to other impl 
                Point overlayPoint;

                if (corner.Equals(ImageCornerEnum.TopLeft))
                {
                    overlayPoint = new Point(0, 0);
                }
                else if (corner.Equals(ImageCornerEnum.TopRight))
                {
                    overlayPoint = new Point(destBmp.Size.Width - bmpToOverlay.Size.Width, 0);
                }
                else if (corner.Equals(ImageCornerEnum.BottomRight))
                {
                    overlayPoint = new Point(destBmp.Size.Width - bmpToOverlay.Size.Width,
                                             destBmp.Size.Height - bmpToOverlay.Size.Height);
                }
                else if (corner.Equals(ImageCornerEnum.Center))
                {
                    overlayPoint = new Point(destBmp.Size.Width / 2 - bmpToOverlay.Size.Width / 2,
                                             destBmp.Size.Height / 2 - bmpToOverlay.Size.Height / 2);
                }
                else
                {
                    overlayPoint = new Point(0,
                                             destBmp.Size.Height - bmpToOverlay.Size.Height);
                }

                return OverlayBitmap(destBmp, bmpToOverlay, overlayAlpha, overlayPoint);
            }

            public static Bitmap OverlayBitmap(this Bitmap destBmp, Bitmap bmpToOverlay, Point overlayPoint)
            {
                return OverlayBitmap(destBmp, bmpToOverlay, 0, overlayPoint);
            }
            public static Bitmap OverlayBitmap(this Bitmap destBmp, Bitmap bmpToOverlay, ImageCornerEnum corner)
            {
                return OverlayBitmap(destBmp, bmpToOverlay, 0, corner);
            }

            ///  
            /// Crops an image, resulting in a new image consisting of the portion of the 
            /// original image contained in a provided bounding rectangle 
            ///  
            /// Bitmap to crop 
            /// Rectangle specifying the range of pixels 
            /// within the image which is to be retained 
            /// New bitmap consisting of the contents of the crop rectangle 
            public static Bitmap CropBitmap(this Bitmap inputBmp, Rectangle cropRectangle)
            {
                //Create a new bitmap object based on the input 
                Bitmap newBmp = new Bitmap(cropRectangle.Width,
                                           cropRectangle.Height,
                                           PixelFormat.Format24bppRgb);//Graphics.FromImage doesn't like Indexed pixel format 

                //Create a graphics object and attach it to the bitmap 
                Graphics newBmpGraphics = Graphics.FromImage(newBmp);

                //Draw the portion of the input image in the crop rectangle 
                //in the graphics object 
                newBmpGraphics.DrawImage(inputBmp,
                                         new Rectangle(0, 0, cropRectangle.Width, cropRectangle.Height),
                                         cropRectangle,
                                         GraphicsUnit.Pixel);

                //Return the bitmap 
                newBmpGraphics.Dispose();

                //newBmp will have a RawFormat of MemoryBmp because it was created 
                //from scratch instead of being based on inputBmp.  Since it it inconvenient 
                //for the returned version of a bitmap to be of a different format, now convert 
                //the scaled bitmap to the format of the source bitmap 
                return ConvertBitmap(newBmp, inputBmp.RawFormat);
            }

            public static String MimeTypeFromImageFormat(ImageFormat format)
            {
                if (format.Equals(ImageFormat.Jpeg))
                {
                    return MIME_JPEG;
                }
                else if (format.Equals(ImageFormat.Gif))
                {
                    return MIME_GIF;
                }
                else if (format.Equals(ImageFormat.Bmp))
                {
                    return MIME_BMP;
                }
                else if (format.Equals(ImageFormat.Tiff))
                {
                    return MIME_TIFF;
                }
                else if (format.Equals(ImageFormat.Png))
                {
                    return MIME_PNG;
                }
                else
                {
                    throw new ArgumentException("Unsupported  image format '" + format + "'", "format");
                }
            }

            public static ImageFormat ImageFormatFromMimeType(String mimeType)
            {
                switch (mimeType)
                {
                    case MIME_JPEG:
                    case MIME_PJPEG:
                        return ImageFormat.Jpeg;

                    case MIME_GIF:
                        return ImageFormat.Gif;

                    case MIME_BMP:
                        return ImageFormat.Bmp;

                    case MIME_TIFF:
                        return ImageFormat.Tiff;

                    case MIME_PNG:
                        return ImageFormat.Png;

                    default:
                        throw new ArgumentException("Unsupported  MIME type '" + mimeType + "'", "mimeType");
                }
            }

            private static ImageCodecInfo FindCodecForType(String mimeType)
            {
                ImageCodecInfo[] imgEncoders = ImageCodecInfo.GetImageEncoders();

                for (int i = 0; i < imgEncoders.GetLength(0); i++)
                {
                    if (imgEncoders[i].MimeType == mimeType)
                    {
                        //Found it 
                        return imgEncoders[i];
                    }
                }

                //No encoders match 
                return null;
            }

            #region 图片移动

            /// <summary>
            /// 图片移动 
            /// </summary>
            /// <param name="bitmap">原图</param>
            /// <param name="x">水平方向</param>
            /// <param name="y">竖直方向</param>
            /// <returns></returns>
            public static Bitmap Move(this Bitmap inputBmp, int x, int y)
            {
                Bitmap bm = new Bitmap(inputBmp.Size.Width - Math.Abs(x), inputBmp.Size.Height - Math.Abs(y));//新建一个图片    长宽高都等于 原图
                Color c = new Color();
              

                if (x >= 0 && y >= 0)//以远点坐标
                {
                    for (int i = 0; i < inputBmp.Width - x; i++)
                    {
                        for (int j = 0; j < inputBmp.Height - y; j++)
                        {
                            c = inputBmp.GetPixel(i, j);
                            bm.SetPixel(i, j, c);
                        }
                    }

                }

                else if (x >= 0 && y <= 0)
                {
                    for (int i = 0; i < inputBmp.Width - x; i++)
                    {
                        for (int j = Math.Abs(y); j < inputBmp.Height; j++)
                        {
                            c = inputBmp.GetPixel(i, j);
                            bm.SetPixel(i + x, j - Math.Abs(y), c);
                            // bm.SetPixel(i, j, c);
                        }
                    }
                }
                else if (x <= 0 && y >= 0)
                {
                    for (int i = Math.Abs(x); i < inputBmp.Width; i++)
                    {
                        for (int j = 0; j < inputBmp.Height - y; j++)
                        {
                            c = inputBmp.GetPixel(i, j);
                            bm.SetPixel(i - Math.Abs(x), j + y, c);
                            //bm.SetPixel(i, j, c);
                        }
                    }
                }
                else if (x <= 0 & y <= 0)
                {
                    for (int i = Math.Abs(x); i < inputBmp.Width; i++)
                    {
                        for (int j = Math.Abs(y); j < inputBmp.Height; j++)
                        {
                            c = inputBmp.GetPixel(i, j);
                            bm.SetPixel(i - Math.Abs(x), j - Math.Abs(y), c);
                            // bm.SetPixel(i, j, c);
                        }
                    }
                }


                return bm;
            }

            #endregion

        }

        public enum ImageCornerEnum
        {
            TopLeft,
            TopRight,
            BottomRight,
            BottomLeft,
            Center
        };

        public enum TiffCompressionEnum
        {
            CCITT3,
            CCITT4,
            LZW,
            RLE,
            None,
            Unspecified
        };
    } 



